package com.myappengine.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.springframework.stereotype.Repository;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.myappengine.exception.AppException;
import com.myappengine.exception.ObjectNotFoundException;
import com.myappengine.model.Clazz;
import com.myappengine.model.Instructor;
import com.myappengine.model.Student;
import com.myappengine.model.UploadedFile;

@Repository
public class StudentDAO {
	
	public void persistStudent(Student student) {
		PersistenceManager pm = null;
		try {
			pm = PMF.getPersistenceManager().getPersistenceManager();
			pm.makePersistent(student);
		} finally {
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<Student> getAllStudents() {
		PersistenceManager pm = null;
		try {
			pm = PMF.getPersistenceManager().getPersistenceManager();
			Query query = pm.newQuery(Student.class);
			List<Student> students = (List<Student>) query.execute();
			return students;
		} finally {
			//pm.close();
		}
	}
	
	public List<Clazz> getClassesByStudent(String studentKey) {
		PersistenceManager pm = null;
		try {
			pm = PMF.getPersistenceManager().getPersistenceManager();
			Student student = pm.getObjectById(Student.class, KeyFactory.stringToKey(studentKey));
			if (student != null) {
				Set<Key> classes = student.getClasses();
				List<Clazz> c = new ArrayList<Clazz>();
				for (Key k : classes) {
					c.add(pm.getObjectById(Clazz.class, k));
				}
				return c;
			}
			return null;
		} finally {
			pm.close();
		}
	}
	
	public Student getStudentByKey(String studentKey) {
		PersistenceManager pm = null;
		try {
			pm = PMF.getPersistenceManager().getPersistenceManager();
			try {
				Student student = pm.getObjectById(Student.class, KeyFactory.stringToKey(studentKey));
				return student;
			} catch (JDOObjectNotFoundException ex) {
				throw new ObjectNotFoundException(ex);
			}
		} finally {
			pm.close();
		}
	}
	
	public void updateStudent(Student student) {
		PersistenceManager pm = PMF.getPersistenceManager().getPersistenceManager();
		Student s = pm.getObjectById(Student.class, student.getKey());
		s.setStudentId(student.getStudentId());
		s.setStudentName(student.getStudentName());
		s.setStudentAge(student.getStudentAge());
		s.getClasses().addAll(student.getClasses());
		pm.close();
	}
	
	public void addStudentToClass(String studentKey, Clazz clazz) {
		PersistenceManager pm = null;
		Transaction transaction = null;
		try {
			pm = PMF.getPersistenceManager().getPersistenceManager();
			transaction = pm.currentTransaction();
			transaction.begin();
			// Transaction contains 3 atomic operations
			// Find student by id
			Student student = pm.getObjectById(Student.class, KeyFactory.stringToKey(studentKey));
			if (student == null) {
				return;
			} else {
				// Persist new class
				clazz.getStudents().add(student.getKey());
				Clazz c = pm.makePersistent(clazz);
				// Update class of student
				student.getClasses().add(c.getKey());
			}
			
			transaction.commit();
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			pm.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<Student> getAllStudent() {
		PersistenceManager pm = PMF.getPersistenceManager().getPersistenceManager();
		Transaction transaction = null;
		try {
			transaction = pm.currentTransaction();
			transaction.begin();
			Query query = pm.newQuery(Student.class);
			List<Student> students = (List<Student>) query.execute();
			transaction.commit();
			return students;
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			pm.close();
		}
	}
	
	public void assignInstructorToStudent(String studentKey, Instructor instructor) {
		PersistenceManager pm = PMF.getPersistenceManager().getPersistenceManager();
		Transaction transaction = null;
		try {
			transaction = pm.currentTransaction();
			transaction.begin();
			Student student = pm.getObjectById(Student.class, KeyFactory.stringToKey(studentKey));
			if (student == null) {
				throw new ObjectNotFoundException();
			} else {
				if (student.getInstructor() != null) {
					return;
				} else {
					// Save Instructor
					instructor.getInstructedStudents().add(student);
					Instructor in = pm.makePersistent(instructor);
					// Update student
					student.setInstructor(in);
				}
			}
			transaction.commit();
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			pm.close();
		}
	}
	
	public void addFileToStudent(String studentKey, UploadedFile file) {
		PersistenceManager pm = PMF.getPersistenceManager().getPersistenceManager();
		Transaction transaction = null;
		try {
			transaction = pm.currentTransaction();
			transaction.begin();
			// Update student
			Student student = pm.getObjectById(Student.class, KeyFactory.stringToKey(studentKey));
			student.getUploadedFiles().add(file);
			transaction.commit();
			System.out.println("OK");
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			pm.close();
		}
	}
	
	public void deleteStudent(String studentKey) {
		PersistenceManager pm = PMF.getPersistenceManager().getPersistenceManager();
		Transaction transaction = null;
		try {
			transaction = pm.currentTransaction();
			transaction.begin();
			Student student = pm.getObjectById(Student.class, KeyFactory.stringToKey(studentKey));
			pm.deletePersistent(student);
			transaction.commit();
		} catch (Exception ex) {
			ex.printStackTrace();
			throw new AppException(ex);
		} finally {
			if (transaction.isActive()) {
				transaction.rollback();
			}
			pm.close();
		}
	}
}
